package com.yangtu.nearbyshop.merc.web;

import com.yangtu.nearbyshop.core.notify.NotifyService;
import com.yangtu.nearbyshop.core.util.ResponseUtil;
import com.yangtu.nearbyshop.core.util.bcrypt.BCryptPasswordEncoder;
import com.yangtu.nearbyshop.db.domain.NearbyshopMerc;
import com.yangtu.nearbyshop.db.service.NearbyshopMercService;
import com.yangtu.nearbyshop.merc.dao.MercInfo;
import com.yangtu.nearbyshop.merc.dao.MercToken;
import com.yangtu.nearbyshop.merc.service.MercCaptchaCodeManager;
import com.yangtu.nearbyshop.merc.service.MercTokenManager;
import com.yangtu.nearbyshop.merc.util.WxResponseCode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.yangtu.nearbyshop.core.notify.NotifyType;
import com.yangtu.nearbyshop.core.util.CharUtil;
import com.yangtu.nearbyshop.core.util.JacksonUtil;
import com.yangtu.nearbyshop.core.util.RegexUtil;
import com.yangtu.nearbyshop.merc.annotation.LoginMerc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 鉴权服务
 */
@RestController
@RequestMapping("/merc/auth")
@Validated
public class MercAuthController {
    private final Log logger = LogFactory.getLog(MercAuthController.class);

    @Autowired
    private NearbyshopMercService mercService;

    @Autowired
    private NotifyService notifyService;

    /**
     * 账号登录
     *
     * @param body    请求内容，{ mercname: xxx, password: xxx }
     * @param request 请求对象
     * @return 登录结果
     */
    @PostMapping("login")
    public Object login(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        if (username == null || password == null) {
            return ResponseUtil.badArgument();
        }

        List<NearbyshopMerc> mercList = mercService.queryByname(username);
        NearbyshopMerc merc = null;
        if (mercList.size() > 1) {
            return ResponseUtil.serious();
        } else if (mercList.size() == 0) {
            return ResponseUtil.fail(WxResponseCode.AUTH_INVALID_ACCOUNT, "商户不存在");
        } else {
            merc = mercList.get(0);
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password, merc.getPassword())) {
            return ResponseUtil.fail(WxResponseCode.AUTH_INVALID_ACCOUNT, "账号密码不对");
        }


        // mercInfo
        MercInfo mercInfo = new MercInfo();
        mercInfo.setNickName(username);
        mercInfo.setAvatarUrl(merc.getAvatar());

        // token
        MercToken mercToken = MercTokenManager.generateToken(merc.getId(), merc.getMercNo());

        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", mercToken.getToken());
        result.put("tokenExpire", mercToken.getExpireTime().toString());

        mercInfo.setMercNo(merc.getMercNo());
        mercInfo.setMobile(merc.getMobile());
        mercInfo.setOrgNo(merc.getOrgNo());
        result.put("mercInfo", mercInfo);

        return ResponseUtil.ok(result);
    }

    /**
     * 请求验证码
     *
     * @param body 手机号码{mobile}
     * @return
     */
    @PostMapping("regCaptcha")
    public Object registerCaptcha(@RequestBody String body) {
        String phoneNumber = JacksonUtil.parseString(body, "mobile");
        if (StringUtils.isEmpty(phoneNumber)) {
            return ResponseUtil.badArgument();
        }
        if (!RegexUtil.isMobileExact(phoneNumber)) {
            return ResponseUtil.badArgumentValue();
        }

        if (!notifyService.isSmsEnable()) {
            return ResponseUtil.fail(WxResponseCode.AUTH_CAPTCHA_UNSUPPORT, "小程序后台验证码服务不支持");
        }
        String code = CharUtil.getRandomNum(6);
        notifyService.notifySmsTemplate(phoneNumber, NotifyType.CAPTCHA, new String[]{code});

        boolean successful = MercCaptchaCodeManager.addToCache(phoneNumber, code);
        if (!successful) {
            return ResponseUtil.fail(WxResponseCode.AUTH_CAPTCHA_FREQUENCY, "验证码未超时1分钟，不能发送");
        }

        return ResponseUtil.ok();
    }

    /**
     * 账号密码重置
     *
     * @param body    请求内容
     *                {
     *                password: xxx,
     *                mobile: xxx
     *                code: xxx
     *                }
     *                其中code是手机验证码，目前还不支持手机短信验证码
     * @param request 请求对象
     * @return 登录结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("reset")
    public Object reset(@RequestBody String body, HttpServletRequest request) {
        String password = JacksonUtil.parseString(body, "password");
        String mobile = JacksonUtil.parseString(body, "mobile");
        String code = JacksonUtil.parseString(body, "code");

        if (mobile == null || code == null || password == null) {
            return ResponseUtil.badArgument();
        }

        //判断验证码是否正确
        String cacheCode = MercCaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code))
            return ResponseUtil.fail(WxResponseCode.AUTH_CAPTCHA_UNMATCH, "验证码错误");

        List<NearbyshopMerc> mercList = mercService.queryByMobile(mobile);
        NearbyshopMerc merc = null;
        if (mercList.size() > 1) {
            return ResponseUtil.serious();
        } else if (mercList.size() == 0) {
            return ResponseUtil.fail(WxResponseCode.AUTH_MOBILE_UNREGISTERED, "手机号未注册");
        } else {
            merc = mercList.get(0);
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        merc.setPassword(encodedPassword);

        if (mercService.updateById(merc,null) == 0) {
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    @PostMapping("logout")
    public Object logout(@LoginMerc Integer mercId) {
        if (mercId == null) {
            return ResponseUtil.unlogin();
        }
        MercTokenManager.removeToken(mercId);
        return ResponseUtil.ok();
    }
}
